package com.alks.function.service.impl.produce;


import com.alks.common.aop.AutoPageAop;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.utils.UserInfoUtil;
import com.alks.entity.data.entity.PcCuttingLsDetail;
import com.alks.entity.data.entity.PcCuttingLsHead;
import com.alks.entity.data.entity.PcCuttingLsLabel;
import com.alks.entity.data.entity.PcLotHead;
import com.alks.entity.data.page.PageRecord;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.ServiceErrorException;
import com.alks.function.data.dto.chengKong.produce.PcLotDetailDto;
import com.alks.function.data.dto.produce.CutPlanLotDto;
import com.alks.function.data.request.produce.CutPlanLotRequest;
import com.alks.function.data.request.produce.CutPlanRequest;
import com.alks.function.mapper.chengKong.PcLotHeadMapper;
import com.alks.function.mapper.produce.CutPlanMapper;
import com.alks.function.service.produce.CutPlanService;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class CutPlanServiceImpl implements CutPlanService {

    @Autowired
    private PcLotHeadMapper pcLotHeadMapper;

    @Autowired
    private CutPlanMapper  cutPlanMapper;

    /**
     * 生成冲裁批次
     * @param request
     * @return
     */
    @Override
    @Transactional
    public ResponseInfo GeneratePunchingBatch(CutPlanRequest request) {
        if (request.getMaxQty()<=0||request.getLsQty()<=0||request.getSizeQty()<=0){
            return ResponseInfo.error("数值必须大于0!");
        }
        if (ObjectUtils.isEmpty(request.getLotNos())){
            return ResponseInfo.error("请选择记录!");
        }
        String companyId = UserIdThread.get().getCompanyId();
        List<PcLotHead> pcLotHeads = pcLotHeadMapper.selectByLotNos(request.getLotNos(), companyId);
        if (request.getLotNos().size()!=pcLotHeads.size()){
            return ResponseInfo.error("部分指令不存在,请核实!");
        }
        for (PcLotHead pcLotHead : pcLotHeads) {
            if (ObjectUtils.isEmpty(pcLotHead)||!"Y".equals(pcLotHead.getCfmFlag())){
                return ResponseInfo.error("指令"+pcLotHead.getLotNo()+"不存在或者未检核,请核实!");
            }
            List<PcCuttingLsLabel> labelList = cutPlanMapper.selectByLotNos(pcLotHead.getLotNo(), pcLotHead.getCompanyId());
            if (!ObjectUtils.isEmpty(labelList)){
                return ResponseInfo.error("指令"+pcLotHead.getLotNo()+"存在已生成轮次标签不能重新处理,请先删除标签数据!");
            }
            Integer countByLotNo = cutPlanMapper.countByLotNo(pcLotHead.getCompanyId(), pcLotHead.getLotNo());
            if (countByLotNo != null&&countByLotNo>0){
                return ResponseInfo.error("指令"+pcLotHead.getLotNo()+"存在已生产的数据不能重新处理!");
            }
            List<PcLotDetailDto> codeDetails = pcLotHeadMapper.getCodeDetails(pcLotHead.getLotNo(),pcLotHead.getCompanyId());
            if (ObjectUtils.isEmpty(codeDetails)){
                return ResponseInfo.error("指令"+pcLotHead.getLotNo()+"无号码明细!");
            }
            List<PcCuttingLsHead> lsHeads = cutPlanMapper.selectByLotNoToPcCuttingLsHead(pcLotHead.getCompanyId(), pcLotHead.getLotNo());
            if (!request.isOverRide()&&!ObjectUtils.isEmpty(lsHeads)){
                return ResponseInfo.error("指令"+pcLotHead.getLotNo()+"轮次资料已存在!");
            }
        }
        batchCutLsGenerate(pcLotHeads, request.getMaxQty(), request.getLsQty(), request.getSizeQty(), request.isOverRide());
        return ResponseInfo.ok("操作成功!");
    }

    /**
     * 冲裁批次
     * @param lotHeads 指令集合
     * @param maxQty 批次订单双数界限
     * @param lshQty 每批次双数
     * @param sizeQty 单号码数量
     * @param overRide true 重新生成
     * @return
     */
    public int batchCutLsGenerate(List<PcLotHead> lotHeads, int maxQty, int lshQty, int sizeQty, boolean overRide) {
        int recordCount = 0;
        UserInfoUtil.UserInfo userInfo = UserInfoUtil.getUserInfo();
        for (PcLotHead lotHead : lotHeads) {
            //为true删除
            if (overRide){
                cutPlanMapper.deleteByLotNoToPcCuttingLsDetail(lotHead.getCompanyId(), lotHead.getLotNo());
                cutPlanMapper.deleteByLotNoToPcCuttingLsHead(lotHead.getCompanyId(), lotHead.getLotNo());
            }
            // 计算总数量
            int totalQty = lotHead.getTotalQty().intValue();
            List<PcLotDetailDto> lotDetails = pcLotHeadMapper.getCodeDetails(lotHead.getLotNo(), lotHead.getCompanyId());
            LocalDateTime now = LocalDateTime.now();
            int realTotalQty = 0;
            for (PcLotDetailDto lotDetail : lotDetails) {
                int qty = lotDetail.getTotalQty().intValue();
                realTotalQty += qty;
            }
            if (realTotalQty!=totalQty){
                throw new ServiceErrorException("指令数量与实际号码数量总和不符,请核实!");
            }
            if (totalQty<maxQty){
                PcCuttingLsHead pcCuttingLsHead = new PcCuttingLsHead();
                pcCuttingLsHead.setCompanyId(lotHead.getCompanyId());
                pcCuttingLsHead.setLotNo(lotHead.getLotNo());
                pcCuttingLsHead.setLsNo(1);
                pcCuttingLsHead.setQty(totalQty);
                pcCuttingLsHead.setSysDate(now);
                pcCuttingLsHead.setUserId(userInfo.getLoginName());
                recordCount+= cutPlanMapper.addPcCuttingLsHead(pcCuttingLsHead);
                for (PcLotDetailDto lotDetail : lotDetails) {
                    PcCuttingLsDetail pcCuttingLsDetail = new PcCuttingLsDetail();
                    pcCuttingLsDetail.setCompanyId(lotHead.getCompanyId());
                    pcCuttingLsDetail.setLotNo(lotHead.getLotNo());
                    pcCuttingLsDetail.setQty(lotDetail.getTotalQty().intValue());
                    pcCuttingLsDetail.setLsNo(1);
                    pcCuttingLsDetail.setSizeNo(lotDetail.getSizeNo());
                    pcCuttingLsDetail.setSizeSeq(BigDecimal.valueOf(Double.valueOf(lotDetail.getSeqNo())));
                    recordCount+=cutPlanMapper.addPcCuttingLsDetail(pcCuttingLsDetail);
                }
                continue;
            }
            float forecastBatch = (float)realTotalQty / lshQty;
            int forecastBatchInt = (int)Math.ceil(forecastBatch);
            Map<Integer, List<PcCuttingLsDetail>> batchNo2DetailMap = new HashMap<>();
            Map<Integer, Integer> batchNo2QtyMap = new HashMap<>();
            List<PcCuttingLsDetail> detailsList = null;
            for (PcLotDetailDto lotDetail : lotDetails) {
                int orderQty = lotDetail.getTotalQty().intValue();
                if (orderQty == 0) {
                    continue;
                }
                // 计算每个批次的每袋数量
                float bagPerBatchFloat = (float)orderQty / sizeQty / forecastBatch;
                int bagPerBatchInt = (int)(bagPerBatchFloat * 100);

                //批次
                int batchNo = 1;
                int remain = 0;
                //根据每批次的每袋数量结算实际批次数量
                while (orderQty > 0){
                    int qty = bagPerBatchInt / 100 * sizeQty;
                    if (qty == 0) {
                        qty = sizeQty;
                        remain = remain + bagPerBatchInt - 100;
                    } else {
                        remain += bagPerBatchInt % 100;
                    }
                    if (remain >= 50) {
                        qty += sizeQty;
                        remain -= 100;
                    }
                    if (orderQty < qty)
                        qty = orderQty;
                    orderQty -= qty;
                    if (orderQty <= sizeQty * 20 / 100) {
                        qty += orderQty;
                        orderQty = 0;
                    }
                    PcCuttingLsDetail pcCuttingLsDetail = new PcCuttingLsDetail();
                    pcCuttingLsDetail.setCompanyId(lotHead.getCompanyId());
                    pcCuttingLsDetail.setLotNo(lotHead.getLotNo());
                    pcCuttingLsDetail.setQty(qty);
                    pcCuttingLsDetail.setLsNo(batchNo);
                    pcCuttingLsDetail.setSizeNo(lotDetail.getSizeNo());
                    pcCuttingLsDetail.setSizeSeq(BigDecimal.valueOf(Double.valueOf(lotDetail.getSeqNo())));
                    detailsList = batchNo2DetailMap.get(batchNo);
                    if (ObjectUtils.isEmpty(detailsList)){
                        detailsList = new ArrayList<>();
                        batchNo2DetailMap.put(batchNo, detailsList);
                    }
                    int batchNoQty = batchNo2QtyMap.getOrDefault(batchNo, 0);
                    batchNoQty += pcCuttingLsDetail.getQty();
                    batchNo2QtyMap.put(batchNo, batchNoQty);
                    detailsList.add(pcCuttingLsDetail);
                    batchNo++;
                    // 如果批次号大于预测批次数量，将剩余的数量添加到当前批次中
                    if (batchNo > forecastBatchInt) {
                        pcCuttingLsDetail.setQty(pcCuttingLsDetail.getQty() + orderQty);
                        batchNoQty += orderQty;
                        orderQty = 0;
                    }
                    batchNo2QtyMap.put(batchNo - 1, batchNoQty);
                }
            }
            for (Integer batchNo : batchNo2DetailMap.keySet()) {
                List<PcCuttingLsDetail> list = batchNo2DetailMap.get(batchNo);
                int batchTotalQty = batchNo2QtyMap.get(batchNo);
                PcCuttingLsHead pcCuttingLsHead = new PcCuttingLsHead();
                pcCuttingLsHead.setCompanyId(lotHead.getCompanyId());
                pcCuttingLsHead.setLotNo(lotHead.getLotNo());
                pcCuttingLsHead.setLsNo(batchNo);
                pcCuttingLsHead.setQty(batchTotalQty);
                pcCuttingLsHead.setSysDate(now);
                pcCuttingLsHead.setUserId(userInfo.getLoginName());
                recordCount+= cutPlanMapper.addPcCuttingLsHead(pcCuttingLsHead);
                int headQty = 0;
                for (PcCuttingLsDetail crd : list) {
                    recordCount+=cutPlanMapper.addPcCuttingLsDetail(crd);
                    headQty += crd.getQty();
                }
                if (batchTotalQty != headQty)
                    throw new ServiceErrorException("实际批次数量不符,请核实");
            }
        }
        return recordCount;
    }

    /**
     * 待安排指令资料
     * @param request
     * @return
     */
    @Override
    @AutoPageAop
    public ResponseInfo loadCuttingUndealList(CutPlanLotRequest request) {
        PageRecord<CutPlanLotDto> list = new PageRecord<>();
        String companyId = UserIdThread.get().getCompanyId();
        request.setCompanyId(companyId);
        List<CutPlanLotDto> dtoList = cutPlanMapper.selectByLotNoList(request);
        for (CutPlanLotDto t : dtoList) {
            int totalQty=t.getOrderQty()+ t.getSurplusQty();
            t.setTotalQty(totalQty);
        }
        PageInfo page =new PageInfo(dtoList);
        list.setList(dtoList);
        list.setTotal(page.getTotal());
        return ResponseInfo.ok(list);
    }

    /**
     * 已安排指令资料
     * @param request
     * @return
     */
    @Override
    @AutoPageAop
    public ResponseInfo loadCuttingDealList(CutPlanLotRequest request) {
        PageRecord<CutPlanLotDto> list = new PageRecord<>();
        String companyId = UserIdThread.get().getCompanyId();
        request.setCompanyId(companyId);
        List<CutPlanLotDto> dtoList = cutPlanMapper.loadCuttingDealList(request);
        for (CutPlanLotDto t : dtoList) {
            int totalQty=t.getOrderQty()+ t.getSurplusQty();
            t.setTotalQty(totalQty);
        }
        PageInfo page =new PageInfo(dtoList);
        list.setList(dtoList);
        list.setTotal(page.getTotal());
        return ResponseInfo.ok(list);
    }

    /**
     * 批次号码明细
     * @param lotNo
     * @return
     */
    @Override
    public ResponseInfo BatchNumberDetails(String lotNo) {
        String companyId = UserIdThread.get().getCompanyId();
        List<PcCuttingLsDetail> numberDetails = cutPlanMapper.getBatchNumberDetails(lotNo, companyId);
        return ResponseInfo.ok(numberDetails);
    }
}
